package com.ztstkj.lzservices.cameras

import android.Manifest
import android.content.ContentValues
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import android.os.Environment
import android.provider.MediaStore
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.camera.core.Camera
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageCapture
import androidx.camera.core.ImageCaptureException
import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.video.MediaStoreOutputOptions
import androidx.camera.video.Quality
import androidx.camera.video.QualitySelector
import androidx.camera.video.Recorder
import androidx.camera.video.Recording
import androidx.camera.video.VideoCapture
import androidx.camera.video.VideoRecordEvent
import androidx.camera.view.PreviewView
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.content.PermissionChecker
import com.blankj.utilcode.util.ToastUtils
import java.io.File
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
var savePath:String=Environment.getExternalStorageDirectory().toString() + "/images"

open class CameraXManager(
    private var activity: ComponentActivity,
    private var previewView: PreviewView
) {

    private var camera: Camera? = null//相机对象
    private var imageCapture: ImageCapture? = null
    private var processCameraProvider: ProcessCameraProvider?=null
    private var preview: Preview?=null
    private var videoCapture: VideoCapture<Recorder>? = null//录像用例
    private var recording: Recording? = null
    private var cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA//当前相机
    private var context: Context = activity.baseContext
    private lateinit var cameraExecutor: ExecutorService

    companion object {
        private const val TAG = "CameraX"
        private const val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS"
        private const val REQUEST_CODE_PERMISSIONS = 10
        private val REQUIRED_PERMISSIONS = arrayOf(
            Manifest.permission.CAMERA,
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.RECORD_AUDIO
        )
    }

    private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
        ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
    }

    open fun initPermission() {
        if (allPermissionsGranted()) {
            startCamera()
        } else {
            ToastUtils.showLong("Permissions not granted by the user")
            ActivityCompat.requestPermissions(
                activity, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS
            )
        }
    }

    // 后置摄像头是否存在
    fun hasBackCamera(): Boolean {
        try {
            val cameraProvider = ProcessCameraProvider.getInstance(activity).get()
            return cameraProvider?.hasCamera(CameraSelector.DEFAULT_BACK_CAMERA) ?: false
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return false
    }

    // 前置摄像头是否存在
    private fun hasFrontCamera(): Boolean {
        val cameraProvider = ProcessCameraProvider.getInstance(activity).get()
        return cameraProvider?.hasCamera(CameraSelector.DEFAULT_FRONT_CAMERA) ?: false
    }

    private fun startCamera() {
        cameraExecutor = Executors.newSingleThreadExecutor()
        // 将相机的生命周期绑定到应用程序进程中  "getInstance"一个进程中只能存在一个进程相机提供程序，可以使用 进行检索。
        val cameraProviderFuture = ProcessCameraProvider.getInstance(activity)
        cameraProviderFuture.addListener(
            {
                processCameraProvider = cameraProviderFuture.get()

                // 创建预览 Preview
                preview = Preview.Builder()
                    .build()
                    .also {
                        it.setSurfaceProvider(previewView.surfaceProvider)
                    }
                imageCapture = ImageCapture.Builder()
                    .setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY)//（最小化延迟模式）
                    .setJpegQuality(100)
                    .build()
                val recorder = Recorder.Builder()
                    .setQualitySelector(QualitySelector.from(Quality.HIGHEST))
                    .build()
//                val imageAnalyzer = ImageAnalysis.Builder()
//                    .build()
//                    .also {
//                        it.setAnalyzer(cameraExecutor, LuminosityAnalyzer { luma ->
//                            Log.d(TAG, "Average luminosity: $luma")
//                        })
//                    }
                videoCapture = VideoCapture.withOutput(recorder)
                // 选择后置摄像头作为默认值
                val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
                try {
                    // 在重新绑定之前取消绑定用例Unbind use cases before rebinding
                    processCameraProvider?.unbindAll()
                    // 将用例绑定到相机 Bind use cases to camera
                    camera = processCameraProvider?.bindToLifecycle(
                        this.activity,
                        cameraSelector,
                        preview,
                        imageCapture
                    )
                } catch (exc: Exception) {
                    exc.printStackTrace()
                    Log.e(TAG, "Use case binding failed", exc)
                }
            },
            // 返回一个将在与此上下文关联的主线程上运行排队任务
            ContextCompat.getMainExecutor(context)
        )
    }

    fun takePhoto(callBack: (String) -> Unit) {
        try {
//            imageCapture = ImageCapture.Builder()
//                .setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY)//（最小化延迟模式）
//                .build()
            val outputOptions = getOutPutOption2()
            imageCapture!!.takePicture(
                outputOptions, ContextCompat.getMainExecutor(context),
                object : ImageCapture.OnImageSavedCallback {
                    override fun onError(exc: ImageCaptureException) {
                        Log.e(TAG, "Photo capture failed: ${exc.message}", exc)
                        ToastUtils.showLong(" 拍照失败 ${exc.message}")
                    }
                    override fun onImageSaved(output: ImageCapture.OutputFileResults) {
                        //ToastUtils.showLong(" 拍照成功 $savedUri")
                        callBack( output.savedUri?.path.toString())
                    }
                })
        } catch (e: Exception) {
            Log.d(TAG, e.message.toString())
            e.printStackTrace()

        }
    }

    /**
     * 捕获视频
     */
    private fun captureVideo() {
        val videoCapture = this.videoCapture ?: return
        val curRecording = recording
        if (curRecording != null) {
            // 停止当前录制
            curRecording.stop()
            recording = null
            return
        }

        val name = SimpleDateFormat(FILENAME_FORMAT, Locale.US)
            .format(System.currentTimeMillis())
        val contentValues = ContentValues().apply {
            put(MediaStore.MediaColumns.DISPLAY_NAME, name)
            put(MediaStore.MediaColumns.MIME_TYPE, "video/mp4")
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
                put(MediaStore.Video.Media.RELATIVE_PATH, "Movies/CameraX-Video")
            }
        }

        val mediaStoreOutputOptions = MediaStoreOutputOptions
            .Builder(this.activity.contentResolver, MediaStore.Video.Media.EXTERNAL_CONTENT_URI)
            .setContentValues(contentValues)
            .build()
        recording = videoCapture.output
            .prepareRecording(this.context, mediaStoreOutputOptions)
            .apply {
                if (PermissionChecker.checkSelfPermission(
                        context,
                        Manifest.permission.RECORD_AUDIO
                    ) ==
                    PermissionChecker.PERMISSION_GRANTED
                ) {
                    withAudioEnabled()
                }
            }
            .start(ContextCompat.getMainExecutor(this.context)) { recordEvent ->
                when (recordEvent) {
                    is VideoRecordEvent.Start -> {
//todo:
                    }

                    is VideoRecordEvent.Finalize -> {
                        if (!recordEvent.hasError()) {
                            ToastUtils.showLong("Video capture succeeded: ${recordEvent.outputResults.outputUri}")
                        } else {
                            recording?.close()
                            recording = null
                            Log.e(TAG, "Video capture ends with error: " + "${recordEvent.error}")
                        }
                    }
                }
            }
    }

    private fun getOutPutOption(): ImageCapture.OutputFileOptions {
        val name = SimpleDateFormat(FILENAME_FORMAT, Locale.US)
            .format(System.currentTimeMillis())
        val contentValues = ContentValues().apply {
            put(MediaStore.MediaColumns.DISPLAY_NAME, name)
            put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
                put(MediaStore.Images.Media.OWNER_PACKAGE_NAME, "Pictures/CameraX-Image")
            }
        }

        val outputOptions = ImageCapture.OutputFileOptions
            .Builder(
                this.activity.contentResolver,
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                contentValues
            )
            .build()
        return outputOptions
    }

    private fun getOutPutOption2(): ImageCapture.OutputFileOptions {
        val mDateFormat = SimpleDateFormat("yyyyMMddHHmmsssss", Locale.US)
        val dir = File(savePath)
        if (!dir.exists() && !dir.mkdirs()) {
            ToastUtils.showLong("images directory not found")
        }
        val file = File(savePath, mDateFormat.format(Date()).toString() + ".jpg")
        val outputOptions = ImageCapture.OutputFileOptions.Builder(file).build()
        return outputOptions
    }

    fun shutDown() {
        processCameraProvider?.unbindAll()
        cameraExecutor.shutdown()
    }

}